1 : <?php
2 : /**
3 : * Container implementation.
4 : *
5 : * PHP Version 5
6 : *
7 : * @category Ding
8 : * @package Container
9 : * @subpackage Impl
10 : * @author Marcelo Gornstein <marcelog@gmail.com>
11 : * @license http://marcelog.github.com/ Apache License 2.0
12 : * @link http://marcelog.github.com/
13 : *
14 : * Copyright 2011 Marcelo Gornstein <marcelog@gmail.com>
15 : *
16 : * Licensed under the Apache License, Version 2.0 (the "License");
17 : * you may not use this file except in compliance with the License.
18 : * You may obtain a copy of the License at
19 : *
20 : * http://www.apache.org/licenses/LICENSE-2.0
21 : *
22 : * Unless required by applicable law or agreed to in writing, software
23 : * distributed under the License is distributed on an "AS IS" BASIS,
24 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25 : * See the License for the specific language governing permissions and
26 : * limitations under the License.
27 : *
28 : */
29 : namespace Ding\Container\Impl;
30 :
31 : use Ding\Helpers\ErrorHandler\ErrorInfo;
32 :
33 : use Ding\Bean\IBeanDefinitionProvider;
34 : use Ding\Cache\Impl\DummyCacheImpl;
35 : use Ding\Bean\Provider\Core;
36 : use Ding\Resource\Impl\IncludePathResource;
37 : use Ding\Resource\Impl\FilesystemResource;
38 : use Ding\Resource\Impl\URLResource;
39 : use Ding\Cache\Locator\CacheLocator;
40 : use Ding\Container\IContainer;
41 : use Ding\Aspect\AspectManager;
42 : use Ding\Aspect\InterceptorDefinition;
43 : use Ding\Aspect\AspectDefinition;
44 : use Ding\Aspect\Interceptor\IDispatcher;
45 : use Ding\Aspect\Interceptor\DispatcherImpl;
46 : use Ding\Reflection\ReflectionFactory;
47 : use Ding\Bean\Lifecycle\BeanLifecycle;
48 : use Ding\Bean\Lifecycle\BeanLifecycleManager;
49 : use Ding\Bean\Factory\Exception\BeanFactoryException;
50 : use Ding\Bean\BeanConstructorArgumentDefinition;
51 : use Ding\Bean\BeanDefinition;
52 : use Ding\Bean\BeanPropertyDefinition;
53 : use Ding\MessageSource\IMessageSource;
54 :
55 : /**
56 : * Container implementation.
57 : *
58 : * PHP Version 5
59 : *
60 : * @category Ding
61 : * @package Container
62 : * @subpackage Impl
63 : * @author Marcelo Gornstein <marcelog@gmail.com>
64 : * @license http://marcelog.github.com/ Apache License 2.0
65 : * @link http://marcelog.github.com/
66 : */
67 : class ContainerImpl implements IContainer
68 : {
69 : /**
70 : * Signals to handle.
71 : * @var array
72 : */
73 : private $_signals = array(
74 : SIGQUIT, SIGHUP, SIGINT, SIGCHLD, SIGTERM, SIGUSR1, SIGUSR2
75 : );
76 : /**
77 : * Logger.
78 : * @var Logger
79 : */
80 : private $_logger;
81 :
82 : /**
83 : * Cache for isDebugEnabled()
84 : * @var boolean
85 : */
86 : private $_logDebugEnabled;
87 :
88 : /**
89 : * Dispatcher to be cloned for proxy.
90 : * @var DispatcherImpl
91 : */
92 : private $_dispatcherTemplate = null;
93 :
94 : /**
95 : * MessageSource implementation.
96 : * @var IMessageSource
97 : */
98 : private $_messageSource = false;
99 : /**
100 : * Default options.
101 : * @var array
102 : */
103 : private static $_options = array(
104 : 'bdef' => array(),
105 : 'properties' => array(),
106 : 'drivers' => array()
107 : );
108 :
109 : /**
110 : * Registered shutdown methods for beans (destroy-methods).
111 : * @var array
112 : */
113 : private $_shutdowners = array();
114 :
115 : /**
116 : * Beans already instantiated.
117 : * @var object[]
118 : */
119 : private $_beans;
120 :
121 : /**
122 : * Holds our beans cache.
123 : * @var ICache
124 : */
125 : private $_beanCache;
126 :
127 : /**
128 : * Beans already instantiated.
129 : * @var BeanDefinition[]
130 : */
131 : private $_beanDefs;
132 :
133 : /**
134 : * Beans aliases.
135 : * @var string[]
136 : */
137 : private $_beanAliases;
138 :
139 : /**
140 : * Holds our bean definitions cache.
141 : * @var ICache
142 : */
143 : private $_beanDefCache;
144 :
145 : /**
146 : * Container instance.
147 : * @var ContainerImpl
148 : */
149 : private static $_containerInstance = false;
150 :
151 : /**
152 : * The aspect manager.
153 : * @var AspectManager
154 : */
155 : private $_aspectManager = null;
156 :
157 : /**
158 : * The lifecycle manager.
159 : * @var BeanLifecycleManager
160 : */
161 : private $_lifecycleManager = null;
162 :
163 : /**
164 : * Resources multiton.
165 : * @var IResource[]
166 : */
167 : private $_resources = false;
168 :
169 : /**
170 : * The event listeners
171 : * @var string[]
172 : */
173 : private $_eventListeners = false;
174 :
175 : /**
176 : * Bean Definition providers.
177 : * @var IBeanDefinitionProvider[]
178 : */
179 : private $_beanDefinitionProviders = array();
180 :
181 : /**
182 : * The last error message is saved, just to avoid logging repeated messages.
183 : * @var string
184 : */
185 : private $_lastErrorMessage;
186 :
187 : /**
188 : * A ReflectionFactory implementation
189 : * @var IReflectionFactory
190 : */
191 : private $_reflectionFactory;
192 :
193 : /**
194 : * A Proxy factory implementation.
195 : * @var Proxy
196 : */
197 : private $_proxyFactory;
198 :
199 : /**
200 : * Properties configured when instantiating the container and by others,
201 : * like when using a PropertiesHolder.
202 : *
203 : * @var string[]
204 : */
205 : private $_properties;
206 :
207 : /**
208 : * Prevent serialization.
209 : *
210 : * @return array
211 : */
212 : public function __sleep()
213 : {
214 1 : return array('_aspectManager', '_lifecycleManager');
215 : }
216 :
217 : /**
218 : * (non-PHPdoc)
219 : * @see Ding\Bean.IBeanDefinitionProvider::getBeanDefinitionByClass()
220 : */
221 : public function getBeanDefinitionByClass($class)
222 : {
223 3 : foreach ($this->_beanDefinitionProviders as $provider) {
224 3 : $beanDefinition = $provider->getBeanDefinitionByClass($class);
225 3 : }
226 3 : }
227 : /**
228 : * Returns a bean definition.
229 : *
230 : * @param string $name Bean name.
231 : *
232 : * @return BeanDefinition
233 : * @throws BeanFactoryException
234 : */
235 : public function getBeanDefinition($name)
236 : {
237 264 : $beanName = $name . '.beandef';
238 264 : if (isset($this->_beanAliases[$name])) {
239 1 : $name = $this->_beanAliases[$name];
240 1 : }
241 264 : if (isset($this->_beanDefs[$name])) {
242 30 : return $this->_beanDefs[$name];
243 : }
244 :
245 264 : $beanDefinition = null;
246 264 : if ($this->_beanDefCache !== null) {
247 264 : $beanDefinition = $this->_beanDefCache->fetch($beanName, $result);
248 264 : }
249 264 : if ($beanDefinition) {
250 64 : $this->_beanDefs[$name] = $beanDefinition;
251 64 : return $beanDefinition;
252 : }
253 264 : foreach ($this->_beanDefinitionProviders as $provider) {
254 264 : $beanDefinition = $provider->getBeanDefinition($name);
255 264 : if ($beanDefinition) {
256 264 : $beanDefinition->setClass($this->_searchAndReplaceProperties(
257 264 : $beanDefinition->getClass()
258 264 : ));
259 264 : break;
260 : }
261 264 : }
262 264 : if (!$beanDefinition) {
263 246 : throw new BeanFactoryException('Unknown bean: ' . $name);
264 : }
265 264 : $beanDefinition = $this->_lifecycleManager->afterDefinition($beanDefinition);
266 264 : $this->_beanDefs[$beanName] = $beanDefinition;
267 264 : $this->_beanDefCache->store($beanName, $beanDefinition);
268 264 : foreach ($beanDefinition->getAliases() as $alias) {
269 16 : $this->_beanAliases[$alias] = $name;
270 264 : }
271 264 : return $beanDefinition;
272 : }
273 :
274 : /**
275 : * Will try to search and replace the properties found in the given
276 : * value.
277 : *
278 : * @param string $value
279 : *
280 : * @return string
281 : */
282 : private function _searchAndReplaceProperties($value)
283 : {
284 264 : if (is_string($value)) {
285 264 : foreach ($this->_properties as $k => $v) {
286 24 : if (strpos($value, $k) !== false) {
287 18 : if (is_string($v)) {
288 18 : $value = str_replace($k, $v, $value);
289 18 : } else {
290 12 : $value = $v;
291 : // Assigned value is not a string, so we cant use
292 : // strpos anymore on it (i.e: cant continue replacing)
293 12 : break;
294 : }
295 18 : }
296 264 : }
297 264 : }
298 264 : return $value;
299 : }
300 :
301 : /**
302 : * Takes care of transforming a scalar value for a property or constructor
303 : * argument, into a an actual value (i.e: if its a resource://, loading it
304 : * first).
305 : *
306 : * @param mixed $value The value
307 : *
308 : * @return mixed
309 : */
310 : private function _loadValue($value)
311 : {
312 264 : $value = $this->_searchAndReplaceProperties($value);
313 264 : if (is_string($value) && strpos($value, 'resource://') === 0) {
314 2 : $value = substr($value, 11);
315 2 : return $this->getResource($value);
316 : }
317 264 : return $value;
318 : }
319 :
320 : /**
321 : * This will resolve a property (or constructor arg) definition to a final
322 : * value, being a bean reference, array of other properties (or
323 : * constructor args), etc.
324 : *
325 : * @param BeanPropertyDefinition|BeanConstructorArgumentDefinition $what
326 : *
327 : * @return void
328 : */
329 : private function _getValueFromDefinition($what)
330 : {
331 264 : $value = null;
332 264 : if ($what->isBean()) {
333 264 : $value = $this->getBean($what->getValue());
334 264 : } else if ($what->isArray()) {
335 53 : $value = array();
336 53 : foreach ($what->getValue() as $k => $v) {
337 53 : $value[$k] = $this->_getValueFromDefinition($v);
338 53 : }
339 264 : } else if ($what->isCode()) {
340 24 : $value = eval($what->getValue());
341 24 : } else {
342 264 : $value = $this->_loadValue($what->getValue());
343 : }
344 264 : return $value;
345 : }
346 :
347 : /**
348 : * Resolves all values for constructor arguments definitions in a
349 : * bean definition.
350 : *
351 : * @param BeanDefinition $definition
352 : *
353 : * @return object
354 : */
355 : private function _getConstructorValuesForDefinition($definition)
356 : {
357 264 : $args = array();
358 264 : foreach ($definition->getArguments() as $argument) {
359 264 : $args[] = $this->_getValueFromDefinition($argument);
360 264 : }
361 264 : return $args;
362 : }
363 :
364 : /**
365 : * Instantiates a bean using the constructor.
366 : *
367 : * @param BeanDefinition $definition
368 : *
369 : * @return object
370 : */
371 : private function _instantiateByConstructor(BeanDefinition $definition)
372 : {
373 264 : $args = $this->_getConstructorValuesForDefinition($definition);
374 264 : $class = $definition->getClass();
375 264 : if ($definition->hasProxyClass()) {
376 24 : $class = $definition->getProxyClassName();
377 24 : }
378 264 : $rClass = $this->_reflectionFactory->getClass($class);
379 264 : if (empty($args)) {
380 264 : return $rClass->newInstanceArgs();
381 : } else {
382 264 : return $rClass->newInstanceArgs($args);
383 : }
384 : }
385 :
386 : /**
387 : * Instantiates a bean using a factory class.
388 : *
389 : * @param BeanDefinition $definition
390 : *
391 : * @return object
392 : */
393 : private function _instantiateByFactoryClass(BeanDefinition $definition)
394 : {
395 264 : $args = $this->_getConstructorValuesForDefinition($definition);
396 264 : return forward_static_call_array(
397 264 : array($definition->getClass(), $definition->getFactoryMethod()),
398 : $args
399 264 : );
400 : }
401 :
402 : /**
403 : * Instantiates a bean using a factory bean.
404 : *
405 : * @param BeanDefinition $definition
406 : *
407 : * @return object
408 : */
409 : private function _instantiateByFactoryBean(BeanDefinition $definition)
410 : {
411 65 : $args = $this->_getConstructorValuesForDefinition($definition);
412 65 : $factoryBean = $this->getBean($definition->getFactoryBean());
413 65 : $refObject = new \ReflectionObject($factoryBean);
414 65 : $factoryMethod = $refObject->getMethod($definition->getFactoryMethod());
415 65 : return $factoryMethod->invokeArgs($factoryBean, $args);
416 : }
417 :
418 : /**
419 : * Instantiates a bean.
420 : *
421 : * @param BeanDefinition $definition
422 : *
423 : * @return object
424 : */
425 : private function _instantiate(BeanDefinition $definition)
426 : {
427 264 : if ($definition->isCreatedByConstructor()) {
428 264 : return $this->_instantiateByConstructor($definition);
429 264 : } else if ($definition->isCreatedWithFactoryBean()) {
430 65 : return $this->_instantiateByFactoryBean($definition);
431 : } else {
432 264 : return $this->_instantiateByFactoryClass($definition);
433 : }
434 : }
435 :
436 : /**
437 : * Creates whatever beans this definition depends on.
438 : *
439 : * @return void
440 : */
441 : private function _createBeanDependencies(BeanDefinition $definition)
442 : {
443 264 : foreach ($definition->getDependsOn() as $depBean) {
444 6 : $this->getBean(trim($depBean));
445 264 : }
446 264 : }
447 :
448 : /**
449 : * Will inject into the given dispatcher the necessary information to
450 : * aspects will be run correctly.
451 : *
452 : * @throws BeanFactoryException
453 : * @return void
454 : */
455 : private function _applyAspect(
456 : $targetClass, AspectDefinition $aspectDefinition, IDispatcher $dispatcher
457 : ) {
458 25 : $rClass = $this->_reflectionFactory->getClass($targetClass);
459 25 : $aspect = $this->getBean($aspectDefinition->getBeanName());
460 25 : foreach ($aspectDefinition->getPointcuts() as $pointcutName) {
461 25 : $pointcut = $this->_aspectManager->getPointcut($pointcutName);
462 25 : if ($pointcut === false) {
463 1 : throw new BeanFactoryException('Could not find pointcut: ' . $pointcutName);
464 : }
465 24 : $expression = $pointcut->getExpression();
466 24 : foreach ($rClass->getMethods() as $method) {
467 24 : $methodName = $method->getName();
468 24 : if (preg_match('/' . $expression . '/', $methodName) === 0) {
469 8 : continue;
470 : }
471 : if (
472 24 : $aspectDefinition->getType() == AspectDefinition::ASPECT_METHOD
473 24 : ) {
474 21 : $dispatcher->addMethodInterceptor($methodName, $aspect, $pointcut->getMethod());
475 21 : } else {
476 5 : $dispatcher->addExceptionInterceptor($methodName, $aspect, $pointcut->getMethod());
477 : }
478 24 : }
479 24 : }
480 24 : }
481 :
482 : /**
483 : * Applies all aspects specifically defined for this bean definition.
484 : *
485 : * @param BeanDefinition $definition
486 : * @param IDispatcher $dispatcher
487 : *
488 : * @return void
489 : */
490 : private function _applySpecificAspects(BeanDefinition $definition, IDispatcher $dispatcher)
491 : {
492 264 : if ($definition->hasAspects()) {
493 17 : foreach ($definition->getAspects() as $aspect) {
494 17 : $this->_applyAspect($definition->getClass(), $aspect, $dispatcher);
495 17 : }
496 17 : }
497 264 : }
498 :
499 : /**
500 : * Looks for any global aspects that may apply to this bean and applies them.
501 : *
502 : * @param BeanDefinition $definition
503 : * @param IDispatcher $dispatcher
504 : *
505 : * @return void
506 : */
507 : private function _applyGlobalAspects(BeanDefinition $definition, IDispatcher $dispatcher)
508 : {
509 264 : $class = $definition->getClass();
510 264 : $rClass = $this->_reflectionFactory->getClass($class);
511 264 : foreach ($this->_aspectManager->getAspects() as $aspect) {
512 27 : $expression = $aspect->getExpression();
513 27 : if (preg_match('/' . $expression . '/', $class) === 0) {
514 27 : $parentClass = $rClass->getParentClass();
515 27 : while($parentClass !== false) {
516 1 : if (preg_match('/' . $expression . '/', $parentClass->getName()) > 0) {
517 1 : $this->_applyAspect($parentClass->getName(), $aspect, $dispatcher);
518 1 : }
519 1 : $parentClass = $parentClass->getParentClass();
520 1 : }
521 27 : } else {
522 7 : $this->_applyAspect($class, $aspect, $dispatcher);
523 : }
524 264 : }
525 264 : }
526 :
527 : /**
528 : * Applies specific bean aspects and global defined aspects.
529 : *
530 : * @param BeanDefinition $definition
531 : *
532 : * @return void
533 : */
534 : private function _applyAspects(BeanDefinition $definition)
535 : {
536 264 : $class = $definition->getClass();
537 264 : if (empty($class)) {
538 1 : return;
539 : }
540 264 : $dispatcher = clone $this->_dispatcherTemplate;
541 264 : $this->_applySpecificAspects($definition, $dispatcher);
542 264 : $this->_applyGlobalAspects($definition, $dispatcher);
543 264 : if ($dispatcher->hasMethodsIntercepted()) {
544 24 : $definition->setProxyClassName(
545 24 : $this->_proxyFactory->create($class, $dispatcher)
546 24 : );
547 24 : }
548 264 : }
549 : /**
550 : * This will create a new bean, injecting all properties and applying all
551 : * aspects.
552 : *
553 : * @throws BeanFactoryException
554 : * @return object
555 : */
556 : private function _createBean(BeanDefinition $definition)
557 : {
558 264 : $this->_lifecycleManager->beforeCreate($definition);
559 264 : $this->_createBeanDependencies($definition);
560 264 : $this->_applyAspects($definition);
561 264 : $bean = $this->_instantiate($definition);
562 264 : $this->_assemble($bean, $definition);
563 264 : $this->_setupInitAndShutdown($bean, $definition);
564 264 : $this->_lifecycleManager->afterCreate($bean, $definition);
565 264 : return $bean;
566 : }
567 :
568 : /**
569 : * Calls init method and register shutdown method.
570 : *
571 : * @param object $bean
572 : * @param BeanDefinition $definition
573 : *
574 : * @return void
575 : */
576 : private function _setupInitAndShutdown($bean, BeanDefinition $definition)
577 : {
578 264 : if ($definition->hasInitMethod()) {
579 23 : $initMethod = $definition->getInitMethod();
580 23 : $bean->$initMethod();
581 23 : }
582 264 : if ($definition->hasDestroyMethod()) {
583 22 : $destroyMethod = $definition->getDestroyMethod();
584 22 : $this->registerShutdownMethod($bean, $destroyMethod);
585 22 : }
586 264 : }
587 : /**
588 : * Assembles a bean (setter injection)
589 : *
590 : * @param mixed $bean
591 : * @param BeanDefinition $beanDefinition
592 : *
593 : * @return void
594 : */
595 : private function _assemble($bean, BeanDefinition $beanDefinition)
596 : {
597 264 : $this->_lifecycleManager->beforeAssemble($bean, $beanDefinition);
598 264 : foreach ($beanDefinition->getProperties() as $property) {
599 264 : $propertyName = $property->getName();
600 264 : $methodName = 'set' . ucfirst($propertyName);
601 264 : $rClass = $this->_reflectionFactory->getClass($beanDefinition->getClass());
602 264 : if ($rClass->hasMethod($methodName)) {
603 264 : $bean->$methodName($this->_getValueFromDefinition($property));
604 264 : }
605 264 : }
606 264 : $this->fillAware($beanDefinition, $bean);
607 264 : $this->_lifecycleManager->afterAssemble($bean, $beanDefinition);
608 264 : }
609 : /**
610 : * Returns a bean.
611 : *
612 : * @param string $name Bean name.
613 : *
614 : * @throws BeanFactoryException
615 : * @return object
616 : */
617 : public function getBean($name)
618 : {
619 264 : $ret = false;
620 264 : $beanDefinition = $this->getBeanDefinition($name);
621 264 : $beanName = $name . '.bean';
622 264 : if ($beanDefinition->isAbstract()) {
623 1 : throw new BeanFactoryException(
624 1 : "Cant instantiate abstract bean: $name"
625 1 : );
626 : }
627 264 : if ($beanDefinition->isPrototype()) {
628 38 : $ret = $this->_createBean($beanDefinition);
629 264 : } else if ($beanDefinition->isSingleton()) {
630 264 : if (isset($this->_beans[$beanName])) {
631 165 : $ret = $this->_beans[$beanName];
632 165 : } else {
633 264 : $ret = $this->_beanCache->fetch($beanName, $result);
634 264 : if (!$ret) {
635 264 : $ret = $this->_createBean($beanDefinition);
636 264 : }
637 264 : $this->_beans[$beanName] = $ret;
638 : }
639 264 : }
640 264 : return $ret;
641 : }
642 :
643 : /**
644 : * This will return a container
645 : *
646 : * @param array $properties Container properties.
647 : *
648 : * @return ContainerImpl
649 : */
650 : public static function getInstance(array $properties = array())
651 : {
652 264 : if (self::$_containerInstance === false) {
653 : // Init cache subsystems.
654 264 : if (isset($properties['ding']['cache'])) {
655 151 : CacheLocator::configure($properties['ding']['cache']);
656 151 : }
657 264 : \Ding\Autoloader\Autoloader::setCache(CacheLocator::getAutoloaderCacheInstance());
658 264 : if (isset($properties['ding']['log4php.properties'])) {
659 264 : \Logger::configure($properties['ding']['log4php.properties']);
660 264 : }
661 264 : self::$_containerInstance = new ContainerImpl($properties['ding']['factory']);
662 260 : }
663 260 : return self::$_containerInstance;
664 : }
665 :
666 : /**
667 : * Register a shutdown (destroy-method) method for a bean.
668 : *
669 : * @param object $bean Bean to call.
670 : * @param string $method Method to call.
671 : *
672 : * @see Ding\Container.IContainer::registerShutdownMethod()
673 : *
674 : * @return void
675 : */
676 : public function registerShutdownMethod($bean, $method)
677 : {
678 22 : $this->_shutdowners[] = array($bean, $method);
679 22 : }
680 :
681 : /**
682 : * Destructor, will call all beans destroy-methods.
683 : *
684 : * @return void
685 : */
686 : public function __destruct()
687 : {
688 16 : foreach ($this->_shutdowners as $shutdownCall) {
689 16 : $bean = $shutdownCall[0];
690 16 : $method = $shutdownCall[1];
691 16 : $bean->$method();
692 16 : }
693 16 : }
694 :
695 : /**
696 : *
697 : * Enter description here ...
698 : * @param unknown_type $messageSource
699 : */
700 : public function setMessageSource(IMessageSource $messageSource)
701 : {
702 14 : $this->_messageSource = $messageSource;
703 14 : }
704 :
705 : /**
706 : * (non-PHPdoc)
707 : * @see Ding\MessageSource.IMessageSource::getMessage()
708 : */
709 : public function getMessage($bundle, $message, array $arguments, $locale = 'default')
710 : {
711 : return
712 3 : $this->_messageSource !== false
713 3 : ? $this->_messageSource->getMessage($bundle, $message, $arguments, $locale)
714 3 : : NULL;
715 : }
716 :
717 : /**
718 : * (non-PHPdoc)
719 : * @see Ding\Resource.IResourceLoader::getResource()
720 : */
721 : public function getResource($location, $context = false)
722 : {
723 : // Missing scheme?
724 8 : $scheme = strpos($location, '://');
725 8 : if ($scheme === false) {
726 1 : $location = FilesystemResource::SCHEME . $location;
727 1 : }
728 : // Already served?
729 8 : if (isset($this->_resources[$location])) {
730 1 : return $this->_resources[$location];
731 : }
732 : // See what kind of resource to return.
733 8 : if (strpos($location, FilesystemResource::SCHEME) === 0) {
734 3 : $resource = new FilesystemResource($location, $context);
735 8 : } else if (strpos($location, IncludePathResource::SCHEME) === 0) {
736 4 : $resource = new IncludePathResource($location, $context);
737 4 : } else {
738 1 : $resource = new URLResource($location, $context);
739 : }
740 8 : $this->_resources[$location] = $resource;
741 8 : return $resource;
742 : }
743 :
744 : /**
745 : * (non-PHPdoc)
746 : * @see Ding\Container.IContainer::eventDispatch()
747 : */
748 : public function eventDispatch($eventName, $data = null)
749 : {
750 14 : $eventName = 'on' . ucfirst($eventName);
751 14 : if (isset($this->_eventListeners[$eventName])) {
752 5 : foreach ($this->_eventListeners[$eventName] as $beanName) {
753 5 : $bean = $this->getBean($beanName);
754 5 : $bean->$eventName($data);
755 5 : }
756 5 : }
757 14 : }
758 :
759 : /**
760 : * (non-PHPdoc)
761 : * @see Ding\Container.IContainer::eventListen()
762 : */
763 : public function eventListen($eventName, $beanName)
764 : {
765 7 : if (!isset($this->_eventListeners[$eventName])) {
766 7 : $this->_eventListeners[$eventName] = array();
767 7 : }
768 7 : $eventName = 'on' . ucfirst($eventName);
769 7 : $this->_eventListeners[$eventName][] = $beanName;
770 7 : }
771 :
772 : /**
773 : * (non-PHPdoc)
774 : * @see Ding\Container.IContainer::registerBeanDefinitionProvider()
775 : */
776 : public function registerBeanDefinitionProvider(IBeanDefinitionProvider $provider)
777 : {
778 264 : $this->_beanDefinitionProviders[] = $provider;
779 264 : }
780 :
781 : /**
782 : * If we dont have a ReflectionFactory yet (i.e: didnt make the call to
783 : * getBean() yet), replace it with this one.
784 : *
785 : * @param string $class The name of a class.
786 : *
787 : * @return ReflectionClass
788 : */
789 : protected function getClass($class)
790 : {
791 264 : return new \ReflectionClass($class);
792 : }
793 :
794 : /**
795 : * Will look for "aware" kind of interfaces and inject whatever necessary.
796 : *
797 : * @param BeanDefinition $def The Bean Definition
798 : * @param object $bean The bean
799 : *
800 : * @return void
801 : */
802 : public function fillAware(BeanDefinition $def, $bean)
803 : {
804 264 : $class = get_class($bean);
805 264 : $rClass = $this->_reflectionFactory->getClass($class);
806 264 : if ($rClass->implementsInterface('Ding\Reflection\IReflectionFactoryAware')) {
807 264 : $bean->setReflectionFactory($this->_reflectionFactory);
808 264 : }
809 264 : if ($rClass->implementsInterface('Ding\Bean\IBeanNameAware')) {
810 1 : $bean->setBeanName($def->getName());
811 1 : }
812 264 : if ($rClass->implementsInterface('Ding\Logger\ILoggerAware')) {
813 190 : $bean->setLogger(\Logger::getLogger($class));
814 190 : }
815 264 : if ($rClass->implementsInterface('Ding\Container\IContainerAware')) {
816 264 : $bean->setContainer($this);
817 264 : }
818 264 : if ($rClass->implementsInterface('Ding\Resource\IResourceLoaderAware')) {
819 260 : $bean->setResourceLoader($this);
820 260 : }
821 264 : if ($rClass->implementsInterface('Ding\Aspect\IAspectManagerAware')) {
822 264 : $bean->setAspectManager($this->_aspectManager);
823 264 : }
824 264 : if ($rClass->implementsInterface('Ding\Bean\IBeanDefinitionProvider')) {
825 264 : $this->registerBeanDefinitionProvider($bean);
826 264 : }
827 264 : if ($rClass->implementsInterface('Ding\Bean\Lifecycle\IAfterConfigListener')) {
828 264 : $this->_lifecycleManager->addAfterConfigListener($bean);
829 264 : }
830 264 : if ($rClass->implementsInterface('Ding\Bean\Lifecycle\IAfterDefinitionListener')) {
831 260 : $this->_lifecycleManager->addAfterDefinitionListener($bean);
832 260 : }
833 264 : if ($rClass->implementsInterface('Ding\Bean\Lifecycle\IBeforeCreateListener')) {
834 1 : $this->_lifecycleManager->addBeforeCreateListener($bean);
835 1 : }
836 264 : if ($rClass->implementsInterface('Ding\Bean\Lifecycle\IAfterCreateListener')) {
837 260 : $this->_lifecycleManager->addAfterCreateListener($bean);
838 260 : }
839 264 : if ($rClass->implementsInterface('Ding\Bean\Lifecycle\IBeforeAssembleListener')) {
840 1 : $this->_lifecycleManager->addBeforeAssembleListener($bean);
841 1 : }
842 264 : if ($rClass->implementsInterface('Ding\Bean\Lifecycle\IAfterAssembleListener')) {
843 1 : $this->_lifecycleManager->addAfterAssembleListener($bean);
844 1 : }
845 264 : if ($rClass->implementsInterface('Ding\Aspect\IAspectProvider')) {
846 189 : $this->_aspectManager->registerAspectProvider($bean);
847 185 : }
848 264 : if ($rClass->implementsInterface('Ding\Aspect\IPointcutProvider')) {
849 185 : $this->_aspectManager->registerPointcutProvider($bean);
850 185 : }
851 264 : }
852 :
853 : /**
854 : * Called when a signal is caught.
855 : *
856 : * @param integer $signo
857 : *
858 : * @return void
859 : */
860 : public function signalHandler($signo)
861 : {
862 2 : $msg = "Caught Signal: $signo";
863 2 : $this->_logger->warn($msg);
864 2 : $this->eventDispatch('dingSignal', $signo);
865 2 : }
866 :
867 : /**
868 : * Called by php after set_error_handler()
869 : *
870 : * @param integer $type
871 : * @param string $message
872 : * @param string $file
873 : * @param integer $line
874 : *
875 : * @return true
876 : */
877 : public function errorHandler($type, $message, $file, $line)
878 : {
879 11 : $msg = "$message in $file:$line";
880 11 : if ($msg == $this->_lastErrorMessage) {
881 1 : return;
882 : }
883 11 : $this->_lastErrorMessage = $msg;
884 11 : $this->_logger->error($msg);
885 11 : $this->eventDispatch(
886 11 : 'dingError', new ErrorInfo($type, $message, $file, $line)
887 11 : );
888 11 : return true;
889 : }
890 :
891 : // @codeCoverageIgnoreStart
892 : /**
893 : * Called by the vm after register_shutdown_function()
894 : *
895 : * @return void
896 : */
897 : public function shutdownHandler()
898 : {
899 : $msg = "Shutting down";
900 : $this->eventDispatch('dingShutdown');
901 : }
902 : // @codeCoverageIgnoreEnd
903 :
904 : /**
905 : * (non-PHPdoc)
906 : * @see Ding\Container.IContainer::registerProperties()
907 : */
908 : public function registerProperties(array $properties)
909 : {
910 264 : foreach ($properties as $key => $value) {
911 24 : if (strncmp($key, 'php.', 4) === 0) {
912 2 : ini_set(substr($key, 4), $value);
913 2 : }
914 24 : $this->_properties['${' . $key . '}'] = $value;
915 264 : }
916 264 : }
917 :
918 : /**
919 : * Constructor.
920 : *
921 : * @param array $options options.
922 : *
923 : * @return void
924 : */
925 : protected function __construct(array $options)
926 : {
927 : // Setup logger.
928 264 : $this->_logger = \Logger::getLogger(get_class($this));
929 264 : $this->_logDebugEnabled = $this->_logger->isDebugEnabled();
930 264 : $soullessArray = array();
931 264 : $this->_beanAliases = $soullessArray;
932 264 : $this->_beanDefs = $soullessArray;
933 264 : $this->_beans = $soullessArray;
934 264 : $this->_shutdowners = $soullessArray;
935 264 : $this->_resources = $soullessArray;
936 264 : $this->_eventListeners = $soullessArray;
937 264 : $this->_properties = $soullessArray;
938 :
939 : // Merge options with our defaults.
940 264 : self::$_options = array_replace_recursive(self::$_options, $options);
941 264 : $this->registerProperties(self::$_options['properties']);
942 264 : $sapi = php_sapi_name();
943 264 : if ($sapi == 'cgi' || $sapi == 'cli') {
944 264 : $handler = array($this, 'signalHandler');
945 264 : foreach ($this->_signals as $signal) {
946 264 : pcntl_signal($signal, $handler);
947 264 : }
948 264 : pcntl_sigprocmask(SIG_UNBLOCK, $this->_signals);
949 264 : }
950 264 : set_error_handler(array($this, 'errorHandler'));
951 264 : register_shutdown_function(array($this, 'shutdownHandler'));
952 :
953 : // We need a lifecycle manager.
954 264 : $this->_lifecycleManager = new BeanLifecycleManager;
955 264 : $this->_dispatcherTemplate = new DispatcherImpl();
956 264 : $this->_aspectManager = new AspectManager();
957 264 : $this->_beanDefCache = DummyCacheImpl::getInstance();
958 264 : $this->_beanCache = DummyCacheImpl::getInstance();
959 264 : $this->registerBeanDefinitionProvider(new Core(self::$_options));
960 264 : $this->_reflectionFactory = $this;
961 264 : $this->_reflectionFactory = $this->getBean('dingReflectionFactory');
962 264 : $this->_proxyFactory = $this->getBean('dingProxyFactory');
963 264 : $this->_beanDefCache = $this->getBean('dingDefinitionsCache');
964 264 : $this->_beanCache = $this->getBean('dingBeanCache');
965 264 : $this->_lifecycleManager = $this->getBean('dingLifecycleManager');
966 264 : $this->_aspectManager = $this->getBean('dingAspectManager');
967 264 : $this->_dispatcherTemplate = $this->getBean('dingAspectCallDispatcher');
968 :
969 : // Set drivers
970 264 : if (isset(self::$_options['bdef']['xml'])) {
971 162 : $xmlDriver = $this->getBean('dingXmlBeanDefinitionProvider');
972 160 : }
973 262 : if (isset(self::$_options['bdef']['yaml'])) {
974 35 : $yamlDriver = $this->getBean('dingYamlBeanDefinitionProvider');
975 33 : }
976 260 : $this->getBean('dingPropertiesDriver');
977 260 : $this->getBean('dingMessageSourceDriver');
978 260 : $this->getBean('dingMethodInjectionDriver');
979 :
980 : // All set, continue.
981 260 : if (isset(self::$_options['bdef']['annotation'])) {
982 105 : $anDriver = $this->getBean('dingAnnotationBeanDefinitionProvider');
983 105 : $this->getBean('dingAnnotationAspectDriver');
984 105 : $this->getBean('dingAnnotationResourceDriver');
985 105 : $this->getBean('dingAnnotationInitDestroyMethodDriver');
986 105 : $this->getBean('dingAnnotationRequiredDriver');
987 105 : $this->getBean('dingMvcAnnotationDriver');
988 105 : }
989 260 : $this->_lifecycleManager->afterConfig();
990 260 : }
991 : }
|